#include "bit.h"

#include <stddef.h>
#include <assert.h>

static void
count_bit(int n, int bit, void *cl)
{
    int *p = (int*)cl;
    if (bit == 1) {
        assert(n == 0 || n == 125);
        *p += 1;
    }
}

static void
test()
{
    Bit_T set = Bit_new(126);
    assert(Bit_length(set) == 126);
    assert(Bit_get(set, 0) == 0);
    assert(Bit_get(set, 125) == 0);

    assert(Bit_put(set, 0, 1) == 0);
    assert(Bit_put(set, 125, 1) == 0);

    assert(Bit_get(set, 0) == 1);
    assert(Bit_get(set, 125) == 1);

    assert(Bit_count(set) == 2);
    int n = 0;
    Bit_map(set, count_bit, &n);
    assert(n == 2);

    Bit_free(&set);
    assert(set == NULL);
}

static void
test_basic()
{
    Bit_T set = Bit_new(126);
    Bit_set(set, 0, 125);
    assert(Bit_count(set) == 126);
    Bit_clear(set, 0, 125);
    assert(Bit_count(set) == 0);

    assert(Bit_put(set, 32, 1) == 0);
    assert(Bit_get(set, 32) == 1);
    assert(Bit_put(set, 32, 0) == 1);
    assert(Bit_get(set, 32) == 0);

    Bit_not(set, 0, 49);
    assert(Bit_count(set) == 50);
    assert(Bit_get(set, 49) == 1);
    assert(Bit_get(set, 50) == 0);

    Bit_free(&set);
}

static void
test_compare()
{
    Bit_T set = Bit_new(200);
    Bit_T set2 = Bit_new(200);

    assert(Bit_eq(set, set2));
    assert(Bit_leq(set, set2));

    Bit_set(set2, 0, 99);
    assert(Bit_lt(set, set2));
    assert(Bit_leq(set, set2));

    Bit_set(set, 0, 98);
    assert(Bit_lt(set, set2));
    assert(Bit_leq(set, set2));

    Bit_set(set, 99, 99);
    assert(Bit_eq(set, set2));
    assert(Bit_leq(set, set2));

    Bit_free(&set);
    Bit_free(&set2);
}

static void
test_set_oper()
{
    Bit_T tmp;
    Bit_T set = Bit_new(200);
    Bit_T set2 = Bit_new(200);

    Bit_set(set, 0, 9);
    Bit_set(set2, 5, 14);

    tmp = Bit_union(set, NULL);
    assert(Bit_eq(tmp, set));
    Bit_free(&tmp);

    tmp = Bit_union(NULL, set2);
    assert(Bit_eq(tmp, set2));
    Bit_free(&tmp);

    tmp = Bit_union(set, set2);
    assert(Bit_count(tmp) == 15);
    assert(Bit_get(tmp, 0) == 1);
    assert(Bit_get(tmp, 14) == 1);
    Bit_free(&tmp);


    tmp = Bit_inter(set, NULL);
    assert(Bit_count(tmp) == 0);
    Bit_free(&tmp);

    tmp = Bit_inter(NULL, set2);
    assert(Bit_count(tmp) == 0);
    Bit_free(&tmp);

    tmp = Bit_inter(set, set2);
    assert(Bit_count(tmp) == 5);
    assert(Bit_get(tmp, 5) == 1);
    assert(Bit_get(tmp, 9) == 1);
    Bit_free(&tmp);


    tmp = Bit_minus(set, NULL);
    assert(Bit_eq(tmp, set));
    Bit_free(&tmp);

    tmp = Bit_minus(NULL, set2);
    assert(Bit_count(tmp) == 0);
    Bit_free(&tmp);

    tmp = Bit_minus(set, set2);
    assert(Bit_count(tmp) == 5);
    assert(Bit_get(tmp, 0) == 1);
    assert(Bit_get(tmp, 4) == 1);
    Bit_free(&tmp);


    tmp = Bit_diff(set, NULL);
    assert(Bit_eq(tmp, set));
    Bit_free(&tmp);

    tmp = Bit_diff(NULL, set2);
    assert(Bit_eq(tmp, set2));
    Bit_free(&tmp);

    tmp = Bit_diff(set, set2);
    assert(Bit_count(tmp) == 10);
    assert(Bit_get(tmp, 0) == 1);
    assert(Bit_get(tmp, 4) == 1);
    assert(Bit_get(tmp, 10) == 1);
    assert(Bit_get(tmp, 14) == 1);
    Bit_free(&tmp);


    Bit_free(&set);
    Bit_free(&set2);
}

int main()
{
    test();
    test_basic();
    test_compare();
    test_set_oper();
    return 0;
}

